package com.niiwoo.civet.account.service.local.trade;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.OrderSuccessAccounting;
import com.niiwoo.civet.account.dao.entity.TransFreezeOrder;
import com.niiwoo.civet.account.dao.entity.TransUnfreezeOrder;
import com.niiwoo.civet.account.dto.bill.AddBillAndChangeBalanceDTO;
import com.niiwoo.civet.account.dto.bill.AddBillDetailDTO;
import com.niiwoo.civet.account.dto.common.MoneyTotalDTO;
import com.niiwoo.civet.account.dto.request.ReceivedRepaymentSuccessAccountingRequestDTO;
import com.niiwoo.civet.account.dto.request.TransFreezeRequestDTO;
import com.niiwoo.civet.account.dto.request.TransUnfreezeRequestDTO;
import com.niiwoo.civet.account.dto.response.OrderSuccessAccountingResponseDTO;
import com.niiwoo.civet.account.dto.response.TransFreezeResponseDTO;
import com.niiwoo.civet.account.dto.response.TransUnfreezeResponseDTO;
import com.niiwoo.civet.account.enums.*;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.civet.account.service.local.MoneyTotalLocalService;
import com.niiwoo.civet.account.service.local.bill.BillFacade;
import com.niiwoo.civet.base.dto.BaseFeeDetailDTO;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.base.enums.OrderRefundTypeEnum;
import com.niiwoo.civet.trade.dto.response.newRefund.RefundFreezeParamResponseDTO;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.LanMaoErrorCodeEnum;
import com.niiwoo.tripod.lanmao.enums.PreprocessingBusinessTypeEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.request.CancelPreTransactionRequest;
import com.niiwoo.tripod.lanmao.request.QueryTransactionRequest;
import com.niiwoo.tripod.lanmao.request.UserAutoPreTransactionRequest;
import com.niiwoo.tripod.lanmao.response.LanMaoResponse;
import com.niiwoo.tripod.lanmao.response.QueryCancelPretransactionResponse;
import com.niiwoo.tripod.lanmao.response.QueryPretransactionResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.Validator;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 交易处理相关门类
 * Created by wangjichao on 2018/4/23.
 */
@Service
@Slf4j
public class TransOrderFacade {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private LanMaoSequence lanMaoSequence;

    @Autowired
    private AccountService accountService;

    @Autowired
    private TransFreezeLocalService transFreezeLocalService;

    @Autowired
    private TransUnfreezeLocalService transUnfreezeLocalService;

    @Autowired
    private OrderSuccessAccountingLocalService orderSuccessAccountingLocalService;

    @Autowired
    private LanMaoDirectService lanMaoDirectService;

    @Autowired
    private BillFacade billFacade;

    @Autowired
    private BillDetailListGenerator billDetailListGenerator;

    @Autowired
    private MoneyTotalLocalService moneyTotalLocalService;

    @Autowired
    private Validator springValidator;


    @Reference(version = "1.0.0")
    private ProjectDubboService projectDubboService;

    /**
     * 还款/垫付交易冻结
     * @param requestDTO
     * @return
     */
    public TransFreezeResponseDTO refundFreeze(TransFreezeRequestDTO requestDTO){
        //还款入参校验
        this.validateRefundFreeze(requestDTO);

        //过期时间校验
        if(requestDTO.getExpireTime().before(new Date())){
            throw new BizException("ACC31003");
        }

        //查询账户,仅判断是否开户，无需判断是否激活，未激活支持还款
        AccountBase accountBase = accountService.loadAccountByIdFromMaster(requestDTO.getRepaymentAccountId());

        //初始化交易冻结订单,单独提交事务
        Date now = new Date();
        TransFreezeOrder transFreezeOrder = new TransFreezeOrder();
        transFreezeOrder.setId(snowflakeIdWorker.nextId());
        transFreezeOrder.setRequestNo(lanMaoSequence.getRequestNo());
        transFreezeOrder.setOrderId(requestDTO.getOrderId());
        transFreezeOrder.setOrderType(requestDTO.getOrderType().getCode());
        transFreezeOrder.setUserId(accountBase.getUserId());
        transFreezeOrder.setAccountId(requestDTO.getRepaymentAccountId());
        transFreezeOrder.setPlatformUserNo(accountBase.getAccountNo());
        transFreezeOrder.setProjectId(requestDTO.getProjectId());
        transFreezeOrder.setAmount(requestDTO.getAmount());
        transFreezeOrder.setStatus(TransFreezeStatusEnum.HANDLING.getValue());
        transFreezeOrder.setCreateTime(now);
        transFreezeOrder.setUpdateTime(now);
        transFreezeLocalService.insertTransFreezeOrder(transFreezeOrder);

        //封装返回值公共参数
        TransFreezeResponseDTO freezeResponseDTO = new TransFreezeResponseDTO();
        freezeResponseDTO.setOrderId(requestDTO.getOrderId());
        freezeResponseDTO.setOrderTypeEnum(requestDTO.getOrderType());
        freezeResponseDTO.setFreezeRequestNo(transFreezeOrder.getRequestNo());
        freezeResponseDTO.setAmount(requestDTO.getAmount());
        freezeResponseDTO.setTransFreezeStatusEnum(TransFreezeStatusEnum.HANDLING);//默认处理中

        //余额不足
        if(accountBase.getAvailableAmount().compareTo(requestDTO.getAmount()) < 0 ){
            transFreezeLocalService.freezeFailure(transFreezeOrder.getId(),"ACC10007","账户余额不足");
            freezeResponseDTO.setTransFreezeStatusEnum(TransFreezeStatusEnum.FAIL);
            return freezeResponseDTO;
        }

        //调用存管交易冻结接口
        UserAutoPreTransactionRequest request = new UserAutoPreTransactionRequest();
        request.setRequestNo(transFreezeOrder.getRequestNo());
        request.setPlatformUserNo(accountBase.getAccountNo());
        //还款
        if(freezeResponseDTO.getOrderTypeEnum() == OrderTypeEnum.REPAYMENT){
            request.setBizType(PreprocessingBusinessTypeEnum.REPAYMENT);
        }
        //垫付
        else if(freezeResponseDTO.getOrderTypeEnum() == OrderTypeEnum.GUARANTEE){
            request.setBizType(PreprocessingBusinessTypeEnum.COMPENSATORY);
        }
        request.setAmount(transFreezeOrder.getAmount());
        request.setProjectNo(transFreezeOrder.getProjectId().toString());
        LanMaoResponse response = null;
        try {
            log.info("懒猫授权预处理接口请求:{}",JSON.toJSONString(request));
            response = lanMaoDirectService.userAutoPreTransaction(request).get();
            log.info("懒猫授权预处理接口响应:{}",JSON.toJSONString(response));
        } catch (Exception e) {
            log.error("懒猫授权预处理接口调用异常:{}",JSON.toJSONString(request),e);
            return freezeResponseDTO; //异常当作处理中，进行补单
        }
        //冻结成功
        if(response.isSuccess()){
            freezeResponseDTO.setTransFreezeStatusEnum(TransFreezeStatusEnum.SUCCESS);
            transFreezeLocalService.freezeSuccess(
                    transFreezeOrder.getId(),this.generateFreezeSuccessBill(requestDTO,transFreezeOrder.getRequestNo()));
        }
        else{
            log.error("懒猫授权预处理接口返回失败:{}",JSON.toJSONString(response));
            freezeResponseDTO.setErrorCode(response.getErrorCode());
            freezeResponseDTO.setErrorMessage(response.getErrorMessage());
            //流水号重复和系统错误两种失败不当作失败处理
            if (!LanMaoErrorCodeEnum.REQUEST_NO_REPEAT.getCode().equals(response.getErrorCode())
                    && !LanMaoErrorCodeEnum.SYSTEM_ERROR.getCode().equals(response.getErrorCode())) {
                transFreezeLocalService.freezeFailure(transFreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
                freezeResponseDTO.setTransFreezeStatusEnum(TransFreezeStatusEnum.FAIL);
            }
        }
        //响应交易中心结果
        return freezeResponseDTO;
    }


    /**
     * 通用交易解冻接口
     */
    public TransUnfreezeResponseDTO transUnfreeze(TransUnfreezeRequestDTO requestDTO){
        //入参校验
        this.validate(requestDTO);
        //首先查询冻结订单
        TransFreezeOrder transFreezeOrder = transFreezeLocalService.queryTransFreezeOrderByFreezeRequestNo(requestDTO.getFreezeRequestNo());
        //冻结订单不存在
        if(transFreezeOrder == null){
            throw new BizException("ACC31001");
        }
        //封装返回值公共参数
        String unfreezeRequestNo = lanMaoSequence.getRequestNo();
        TransUnfreezeResponseDTO transUnfreezeResponseDTO = new TransUnfreezeResponseDTO();
        transUnfreezeResponseDTO.setOrderId(transFreezeOrder.getOrderId());
        transUnfreezeResponseDTO.setOrderTypeEnum(OrderTypeEnum.enumOf(transFreezeOrder.getOrderType()));
        transUnfreezeResponseDTO.setUnfreezeRequestNo(unfreezeRequestNo);

        //如果没有传递金额默认全额解冻
        BigDecimal unfreezeAmount = requestDTO.getAmount();//解冻金额
        if(unfreezeAmount == null){
            unfreezeAmount = transFreezeOrder.getAmount();
        }
        transUnfreezeResponseDTO.setAmount(unfreezeAmount);

        //初始化解冻订单
        Date now = new Date();
        TransUnfreezeOrder transUnfreezeOrder = new TransUnfreezeOrder();
        transUnfreezeOrder.setId(snowflakeIdWorker.nextId());
        transUnfreezeOrder.setRequestNo(unfreezeRequestNo);
        transUnfreezeOrder.setOrderId(transFreezeOrder.getOrderId());
        transUnfreezeOrder.setOrderType(transFreezeOrder.getOrderType());
        transUnfreezeOrder.setFreezeId(transFreezeOrder.getId());
        transUnfreezeOrder.setFreezeRequestNo(transFreezeOrder.getRequestNo());
        transUnfreezeOrder.setUserId(transFreezeOrder.getUserId());
        transUnfreezeOrder.setAccountId(transFreezeOrder.getAccountId());
        transUnfreezeOrder.setPlatformUserNo(transFreezeOrder.getPlatformUserNo());
        transUnfreezeOrder.setProjectId(transFreezeOrder.getProjectId());
        transUnfreezeOrder.setAmount(unfreezeAmount);
        transUnfreezeOrder.setStatus(TransUnfreezeStatusEnum.HANDLING.getValue());
        transUnfreezeOrder.setCreateTime(now);
        transUnfreezeOrder.setUpdateTime(now);

        try{
            transUnfreezeLocalService.transUnfreezeInitSynchronized(transFreezeOrder.getId(),transUnfreezeOrder);
        }catch(BizException bizException){
            //已全额解冻幂等返回成功
            if("ACC31004".equals(bizException.getErrorCode())){
                transUnfreezeResponseDTO.setTransUnfreezeStatusEnum(TransUnfreezeStatusEnum.SUCCESS);
                return transUnfreezeResponseDTO;
            }
            //存在未处理完成的冻结订单直接返回处理中
            else if("ACC31005".equals(bizException.getErrorCode())){
                transUnfreezeResponseDTO.setTransUnfreezeStatusEnum(TransUnfreezeStatusEnum.HANDLING);
                return transUnfreezeResponseDTO;
            }
        }

        //调用存管解冻接口
        CancelPreTransactionRequest request = new CancelPreTransactionRequest();
        request.setRequestNo(transUnfreezeOrder.getRequestNo());
        request.setPreTransactionNo(transUnfreezeOrder.getFreezeRequestNo());
        request.setAmount(transUnfreezeOrder.getAmount());
        LanMaoResponse response = null;
        try {
            log.info("懒猫取消预处理接口请求:{}",JSON.toJSONString(request));
            response = lanMaoDirectService.cancelPreTransaction(request).get();
            log.info("懒猫取消预处理接口响应:{}",JSON.toJSONString(response));
        } catch (Exception e) {
            log.error("懒猫取消预处理接口调用异常:{}",JSON.toJSONString(request),e);
            transUnfreezeResponseDTO.setTransUnfreezeStatusEnum(TransUnfreezeStatusEnum.HANDLING);
            return transUnfreezeResponseDTO;
        }
        //取消成功
        if(response.isSuccess()){
            transUnfreezeResponseDTO.setTransUnfreezeStatusEnum(TransUnfreezeStatusEnum.SUCCESS);
            transUnfreezeLocalService.unfreezeSuccess(transFreezeOrder.getId(),transUnfreezeOrder.getId());
        }else{
            log.error("懒猫取消预处理接口返回失败:{}",JSON.toJSONString(response));
            transUnfreezeResponseDTO.setErrorCode(response.getErrorCode());
            transUnfreezeResponseDTO.setErrorMessage(response.getErrorMessage());
            //流水号重复和系统错误两种失败不当作失败处理
            if (!LanMaoErrorCodeEnum.REQUEST_NO_REPEAT.getCode().equals(response.getErrorCode())
                    && !LanMaoErrorCodeEnum.SYSTEM_ERROR.getCode().equals(response.getErrorCode())) {
                transUnfreezeResponseDTO.setTransUnfreezeStatusEnum(TransUnfreezeStatusEnum.FAIL);
                transUnfreezeLocalService.unfreezeFailure(transUnfreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
            }
        }
        return transUnfreezeResponseDTO;
    }


    /**
     * @param orderId
     * @param orderType
     * @return
     */
    public TransFreezeResponseDTO queryTransFreeze(Long orderId,OrderTypeEnum orderType){
        //参数校验
        Assert.notNull(orderId,"orderId不能为空");
        Assert.notNull(orderType,"orderType不能为空");

        //首先查询冻结订单
        TransFreezeOrder transFreezeOrder = transFreezeLocalService.queryTransFreezeOrderByIdAndType(orderId,orderType);
        //查询冻结订单不存在
        if(transFreezeOrder == null){
            throw new BizException("ACC31001");
        }
        //封装返回值
        TransFreezeResponseDTO transFreezeResponseDTO = new TransFreezeResponseDTO();
        transFreezeResponseDTO.setOrderId(transFreezeOrder.getOrderId());
        transFreezeResponseDTO.setOrderTypeEnum(OrderTypeEnum.enumOf(transFreezeOrder.getOrderType()));
        transFreezeResponseDTO.setAmount(transFreezeOrder.getAmount());
        transFreezeResponseDTO.setFreezeRequestNo(transFreezeOrder.getRequestNo());
        transFreezeResponseDTO.setTransFreezeStatusEnum(TransFreezeStatusEnum.enumOf(transFreezeOrder.getStatus()));
        transFreezeResponseDTO.setUnfreezeAmount(transFreezeOrder.getUnfreezeAmount());
        transFreezeResponseDTO.setTransUnfreezeDegreeEnum(TransUnfreezeDegreeEnum.enumOf(transFreezeOrder.getUnfreezeDegree()));
        transFreezeResponseDTO.setErrorCode(transFreezeOrder.getErrorCode());
        transFreezeResponseDTO.setErrorMessage(transFreezeOrder.getErrorMessage());
        return transFreezeResponseDTO;
    }


    /**
     * 回款成功记账接口
     * @param requestDTO
     * @return
     */
    @Transactional
    public OrderSuccessAccountingResponseDTO receivedRepaymentSuccessAccounting(ReceivedRepaymentSuccessAccountingRequestDTO requestDTO){
        //参数校验
        this.validateReceivedRepaymentSuccessAccounting(requestDTO);

        OrderSuccessAccountingResponseDTO responseDTO = new OrderSuccessAccountingResponseDTO();
        //查询记账记录
        OrderSuccessAccounting existAccounting =
                orderSuccessAccountingLocalService.queryOrderSuccessAccountingByOrderIdAndOrderType(requestDTO.getOrderId(),requestDTO.getOrderType());
        //如果已经记账，幂等返回
        if(existAccounting != null){
            log.info("还款记账幂命中：{}",JSON.toJSONString(requestDTO));
            return responseDTO;
        }

        //插入幂等记账表
        orderSuccessAccountingLocalService.insertOrderSuccessAccounting(requestDTO.getOrderId(), requestDTO.getOrderType());

        //回款记账逻辑
        AddBillAndChangeBalanceDTO addBillAndChangeBalanceDTO = this.generateReceivedRepaymentSuccessBill(requestDTO);
        billFacade.addBillAndChangeBalance(addBillAndChangeBalanceDTO);

        log.info("回款成功记账完成 MoneyTotal维护:{}", JSON.toJSONString(requestDTO));
        //moneytotal维护
        this.receivedRepaymentSuccessMoneyTotalProcess(requestDTO);
        return responseDTO;
    }


    /**
     * 回款成功双边moneytotal维护
     * @param requestDTO
     */
    private void receivedRepaymentSuccessMoneyTotalProcess(ReceivedRepaymentSuccessAccountingRequestDTO requestDTO){
        log.info("receivedRepaymentSuccessMoneyTotalProcess requestDTO:{}", JSON.toJSONString(requestDTO));
        boolean receiveSkip = false;
        boolean repaymentSkip = false;

        //担保机构不做moneytotal汇总
        AccountBase repaymentAccount = accountService.loadAccountById(requestDTO.getRepaymentAccountId());
        log.info("receivedRepaymentSuccessMoneyTotalProcess repaymentAccount:{}", JSON.toJSONString(repaymentAccount));
        if(UserRoleEnum.GUARANTEECORP == UserRoleEnum.enumOf(repaymentAccount.getAccountRole())
                || UserRoleEnum.COLLABORATOR == UserRoleEnum.enumOf(repaymentAccount.getAccountRole())){
            repaymentSkip = true;
        }

        //收款人账户
        AccountBase receiveAccount = accountService.loadAccountById(requestDTO.getReceivedAccountId());
        log.info("receivedRepaymentSuccessMoneyTotalProcess receiveAccount:{}", JSON.toJSONString(receiveAccount));
        if(UserRoleEnum.GUARANTEECORP == UserRoleEnum.enumOf(receiveAccount.getAccountRole())
                || UserRoleEnum.COLLABORATOR == UserRoleEnum.enumOf(receiveAccount.getAccountRole())){
            receiveSkip = true;
        }
        //moneytotal列表
        List<MoneyTotalDTO> moneyTotalDTOs = new ArrayList<>();


        if(!repaymentSkip){
            //借款方冻结金额 减
            MoneyTotalDTO repaymentUnfreezeMoneyTotal = new MoneyTotalDTO();
            repaymentUnfreezeMoneyTotal.setAccountId(repaymentAccount.getId());
            repaymentUnfreezeMoneyTotal.setUserId(repaymentAccount.getUserId());
            repaymentUnfreezeMoneyTotal.setAmount(requestDTO.getAmount().negate());
            repaymentUnfreezeMoneyTotal.setAmountType(AccountAmountTypeEnum.REPAYMENT_FREEZE);
            moneyTotalDTOs.add(repaymentUnfreezeMoneyTotal);

            //借款方累计还款金额 加
            MoneyTotalDTO repaymentAlreadyRefund = new MoneyTotalDTO();
            repaymentAlreadyRefund.setAccountId(repaymentAccount.getId());
            repaymentAlreadyRefund.setUserId(repaymentAccount.getUserId());
            repaymentAlreadyRefund.setAmount(requestDTO.getAmount());
            repaymentAlreadyRefund.setAmountType(AccountAmountTypeEnum.REPAYMENT_TOTAL);
            moneyTotalDTOs.add(repaymentAlreadyRefund);
        }

        List<BaseFeeDetailDTO> feeDetailDTOList = requestDTO.getFeeDetailDTOList();
        MoneyTotalDTO repaymentFeeOut = null;//还款方费用支出
        MoneyTotalDTO receiveFeeIn = null; //收款方收入
        MoneyTotalDTO receiveFeeOut = null; //收款方支出

        //回款方待收利息 减
        if(requestDTO.getExpectInterest().compareTo(BigDecimal.ZERO) > 0) {
            //减去的待收利息需要包括expectInterest，例如提前结清场景  也只有提前结清场景 expectInterest 大于0
            receiveFeeOut = new MoneyTotalDTO();
            receiveFeeOut.setAccountId(receiveAccount.getId());
            receiveFeeOut.setUserId(receiveAccount.getUserId());
            receiveFeeOut.setAmount(requestDTO.getExpectInterest().negate());
            receiveFeeOut.setAmountType(AccountAmountTypeEnum.DUE_IN_INTEREST);
            moneyTotalDTOs.add(receiveFeeOut);
        }


        log.info("处理moneyTotal费用明细：{},orderId:{},出款方跳过：{},收款方跳过:{}",
                JSON.toJSONString(feeDetailDTOList),
                requestDTO.getOrderId(),
                repaymentSkip,
                receiveSkip);
        for(BaseFeeDetailDTO feeDetailDTO : feeDetailDTOList){
            if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.CAPITAL){
                if(!receiveSkip){
                    //收款方 待收本金 减
                    receiveFeeOut  = new MoneyTotalDTO();
                    receiveFeeOut.setAccountId(receiveAccount.getId());
                    receiveFeeOut.setUserId(receiveAccount.getUserId());
                    receiveFeeOut.setAmount(feeDetailDTO.getAmount().negate());
                    receiveFeeOut.setAmountType(AccountAmountTypeEnum.DUE_IN_CORPUS);
                    moneyTotalDTOs.add(receiveFeeOut);
                }
            }
            else if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.INTEREST){
                if(!receiveSkip){
                    //收款方 待收利息 减
                    receiveFeeOut  = new MoneyTotalDTO();
                    receiveFeeOut.setAccountId(receiveAccount.getId());
                    receiveFeeOut.setUserId(receiveAccount.getUserId());
                    receiveFeeOut.setAmount(feeDetailDTO.getAmount().negate());
                    receiveFeeOut.setAmountType(AccountAmountTypeEnum.DUE_IN_INTEREST);
                    moneyTotalDTOs.add(receiveFeeOut);

                    //如果是利息的话收款方累计收益加
                    receiveFeeIn = new MoneyTotalDTO();
                    receiveFeeIn.setAccountId(receiveAccount.getId());
                    receiveFeeIn.setUserId(receiveAccount.getUserId());
                    receiveFeeIn.setAmount(requestDTO.getCreditorSaleInterest() == null ? feeDetailDTO.getAmount() : feeDetailDTO.getAmount().subtract(requestDTO.getCreditorSaleInterest()));
                    receiveFeeIn.setAmountType(AccountAmountTypeEnum.INVEST_INCOME);
                    moneyTotalDTOs.add(receiveFeeIn);
                }
                if(!repaymentSkip){
                    //还款方累计借款利息支出 加
                    repaymentFeeOut = new MoneyTotalDTO();
                    repaymentFeeOut.setAccountId(repaymentAccount.getId());
                    repaymentFeeOut.setUserId(repaymentAccount.getUserId());
                    repaymentFeeOut.setAmount(feeDetailDTO.getAmount());
                    repaymentFeeOut.setAmountType(AccountAmountTypeEnum.BORROW_INTEREST);
                    moneyTotalDTOs.add(repaymentFeeOut);
                }
            }
            else if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.PENALTY){
                if(!repaymentSkip){
                    //还款方累计借款利息罚息支出 加
                    repaymentFeeOut = new MoneyTotalDTO();
                    repaymentFeeOut.setAccountId(repaymentAccount.getId());
                    repaymentFeeOut.setUserId(repaymentAccount.getUserId());
                    repaymentFeeOut.setAmount(feeDetailDTO.getAmount());
                    repaymentFeeOut.setAmountType(AccountAmountTypeEnum.BORROW_PENALTY_FEE);
                    moneyTotalDTOs.add(repaymentFeeOut);
                }
            }
            //平台管理费
            else if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.MANAGEMENT_FEE){
                if(!repaymentSkip){
                    //还款方累计平台管理费支出  加
                    repaymentFeeOut = new MoneyTotalDTO();
                    repaymentFeeOut.setAccountId(repaymentAccount.getId());
                    repaymentFeeOut.setUserId(repaymentAccount.getUserId());
                    repaymentFeeOut.setAmount(feeDetailDTO.getAmount());
                    repaymentFeeOut.setAmountType(AccountAmountTypeEnum.BORROW_PLATFORM_SERVICE_FEE);
                    moneyTotalDTOs.add(repaymentFeeOut);
                }
            }
            //担保服务费
            else if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.GUARANTEE_FEE){
                if(!repaymentSkip){
                    //还款方借款费用支出 担保服务费支出 加
                    repaymentFeeOut = new MoneyTotalDTO();
                    repaymentFeeOut.setAccountId(repaymentAccount.getId());
                    repaymentFeeOut.setUserId(repaymentAccount.getUserId());
                    repaymentFeeOut.setAmount(feeDetailDTO.getAmount());
                    repaymentFeeOut.setAmountType(AccountAmountTypeEnum.BORROW_GUARANTEE_SERVICE_FEE);
                    moneyTotalDTOs.add(repaymentFeeOut);
                }
            }
            //累计咨询服务费
            else if(feeDetailDTO.getFeeTypeEnum() == FeeTypeEnum.CONSULTING_FEE){
                if(!repaymentSkip){
                    //还款方借款费用支出 咨询服务费 加
                    repaymentFeeOut = new MoneyTotalDTO();
                    repaymentFeeOut.setAccountId(repaymentAccount.getId());
                    repaymentFeeOut.setUserId(repaymentAccount.getUserId());
                    repaymentFeeOut.setAmount(feeDetailDTO.getAmount());
                    repaymentFeeOut.setAmountType(AccountAmountTypeEnum.BORROW_CONSULTING_FEE);
                    moneyTotalDTOs.add(repaymentFeeOut);
                }
            }
        }
        log.info("receivedRepaymentSuccessMoneyTotalProcess moneyTotalDTOs:{},orderId:{}", JSON.toJSONString(moneyTotalDTOs),requestDTO.getOrderId());
        if(!CollectionUtils.isEmpty(moneyTotalDTOs)){
            moneyTotalLocalService.moneyTotal(moneyTotalDTOs);
        }

    }



    /**
     * 还款成功记账接口
     * @param freezeRequestNo
     * @return
     */
    public OrderSuccessAccountingResponseDTO repaymentSuccessAccounting(String freezeRequestNo){
        //参数校验
        Assert.hasLength(freezeRequestNo,"freezeRequestNo不能为空");

        //查询冻结订单
        TransFreezeOrder transFreezeOrder = transFreezeLocalService.queryTransFreezeOrderByFreezeRequestNo(freezeRequestNo);
        if(transFreezeOrder == null){
            throw new BizException("ACC31001");
        }

        OrderSuccessAccountingResponseDTO responseDTO = new OrderSuccessAccountingResponseDTO();
        //修改账单状态为成功
        billFacade.successBillByOrderId(
                transFreezeOrder.getUserId(),
                String.valueOf(transFreezeOrder.getOrderId()),
                OrderTypeEnum.enumOf(transFreezeOrder.getOrderType()));

        return responseDTO;
    }

    /**
     * 生成冻结成功记账对象
     * @param freezeRequestDTO
     * @return
     */
    private AddBillAndChangeBalanceDTO generateFreezeSuccessBill(TransFreezeRequestDTO freezeRequestDTO,String freezeRequestNo){
        AddBillAndChangeBalanceDTO addBillAndChangeBalanceDTO = new AddBillAndChangeBalanceDTO();
        addBillAndChangeBalanceDTO.setAccountId(freezeRequestDTO.getRepaymentAccountId());
        addBillAndChangeBalanceDTO.setAmount(freezeRequestDTO.getAmount());
        addBillAndChangeBalanceDTO.setInoutType(InoutTypeEnum.OUT_TYPE);
        addBillAndChangeBalanceDTO.setOrderId(freezeRequestDTO.getOrderId());
        addBillAndChangeBalanceDTO.setOrderType(freezeRequestDTO.getOrderType());
        addBillAndChangeBalanceDTO.setRequestNo(freezeRequestNo);
        addBillAndChangeBalanceDTO.setStatus(BillStatusEnum.HANDLING);
        addBillAndChangeBalanceDTO.setChannelCode(ChannelCodeEnum.APP);
        addBillAndChangeBalanceDTO.setProjectId(freezeRequestDTO.getProjectId());
        addBillAndChangeBalanceDTO.setProjectType(freezeRequestDTO.getBorrowProjectTypeEnum());
        addBillAndChangeBalanceDTO.setProjectTitle(freezeRequestDTO.getProjectTitle());
        addBillAndChangeBalanceDTO.setCurrentPeriod(freezeRequestDTO.getCurrentPeriod());
        addBillAndChangeBalanceDTO.setTotalPeriod(freezeRequestDTO.getTotalPeriods());

        //生成明细
        List<AddBillDetailDTO> addBillDetailDTOList = billDetailListGenerator.generateRepaymentBillDetailList(
                freezeRequestDTO.getOrderType(),
                freezeRequestDTO.getOrderRefundTypeEnum(),
                freezeRequestDTO.getFeeDetailDTOList());

        //账单类目转换失败
        if(addBillDetailDTOList == null || addBillDetailDTOList.isEmpty()){
            throw new BizException("ACC30001");
        }

        //关联明细
        addBillAndChangeBalanceDTO.setAddBillDetailDTOList(addBillDetailDTOList);

        return addBillAndChangeBalanceDTO;
    }

    /**
     * 根据订单ID查询交易中心原冻结请求相关参数
     * 用于冻结补单获取冻结成功结果后续流程执行
     * @param orderId
     * @return
     */
    private TransFreezeRequestDTO queryRefundFreezeParam(Long orderId){
        TransFreezeRequestDTO transFreezeRequestDTO = null;
        RefundFreezeParamResponseDTO freezeParamResponseDTO = null;
        try{
            freezeParamResponseDTO = projectDubboService.queryRefundFreezeParam(orderId);
        }catch(Exception e){
            log.error("冻结补单查询冻结请求异常：{}",orderId,e);
            throw e;
        }
        log.info("冻结补单查询冻结请求参数结果：{}",JSON.toJSONString(freezeParamResponseDTO));
        if(freezeParamResponseDTO == null){
            log.info("冻结补单查询冻结请求返回空：{}",orderId);
            return null;
        }
        //封装为冻结请求对象
        transFreezeRequestDTO = new TransFreezeRequestDTO();
        transFreezeRequestDTO.setOrderId(freezeParamResponseDTO.getOrderId());
        if(freezeParamResponseDTO.getOrderTypeEnum() != null){
            transFreezeRequestDTO.setOrderType(OrderTypeEnum.enumOf(freezeParamResponseDTO.getOrderTypeEnum()));
        }
        if(transFreezeRequestDTO.getOrderRefundTypeEnum() != null){
            transFreezeRequestDTO.setOrderRefundTypeEnum(OrderRefundTypeEnum.enumOf(freezeParamResponseDTO.getOrderRefundTypeEnum()));
        }
        transFreezeRequestDTO.setProjectId(freezeParamResponseDTO.getProjectId());
        transFreezeRequestDTO.setBorrowProjectTypeEnum(freezeParamResponseDTO.getBorrowProjectTypeEnum());
        transFreezeRequestDTO.setProjectTitle(freezeParamResponseDTO.getProjectTitle());
        transFreezeRequestDTO.setCurrentPeriod(freezeParamResponseDTO.getCurrentPeriod());
        transFreezeRequestDTO.setTotalPeriods(freezeParamResponseDTO.getTotalPeriods());
        transFreezeRequestDTO.setRepaymentAccountId(freezeParamResponseDTO.getRepaymentAccountId());
        transFreezeRequestDTO.setAmount(freezeParamResponseDTO.getAmount());
        transFreezeRequestDTO.setFeeDetailDTOList(freezeParamResponseDTO.getFeeDetailDTOList());
        return transFreezeRequestDTO;
    }


    /**
     * 生成回款记账对象
     * @param requestDTO
     * @return
     */
    private AddBillAndChangeBalanceDTO generateReceivedRepaymentSuccessBill(ReceivedRepaymentSuccessAccountingRequestDTO requestDTO){
        AddBillAndChangeBalanceDTO addBillAndChangeBalanceDTO = new AddBillAndChangeBalanceDTO();
        addBillAndChangeBalanceDTO.setAccountId(requestDTO.getReceivedAccountId());
        addBillAndChangeBalanceDTO.setAmount(requestDTO.getAmount());
        addBillAndChangeBalanceDTO.setInoutType(InoutTypeEnum.IN_TYPE);
        addBillAndChangeBalanceDTO.setOrderId(requestDTO.getOrderId());
        addBillAndChangeBalanceDTO.setOrderType(requestDTO.getOrderType());
        addBillAndChangeBalanceDTO.setRequestNo(requestDTO.getDetailRequestNo());
        addBillAndChangeBalanceDTO.setStatus(BillStatusEnum.SUCCESS);
        addBillAndChangeBalanceDTO.setChannelCode(ChannelCodeEnum.APP);
        addBillAndChangeBalanceDTO.setProjectId(requestDTO.getProjectId());
        addBillAndChangeBalanceDTO.setProjectType(requestDTO.getBorrowProjectTypeEnum());
        addBillAndChangeBalanceDTO.setProjectTitle(requestDTO.getProjectTitle());
        addBillAndChangeBalanceDTO.setCurrentPeriod(requestDTO.getCurrentPeriod());
        addBillAndChangeBalanceDTO.setTotalPeriod(requestDTO.getTotalPeriods());
        addBillAndChangeBalanceDTO.setInvestId(requestDTO.getInvestId());
        addBillAndChangeBalanceDTO.setRelationAccountId(requestDTO.getRepaymentAccountId());

        //生成回款明细
        List<AddBillDetailDTO> addBillDetailDTOList = billDetailListGenerator.generateReceiveRepaymentBillDetailList(
                requestDTO.getBusinessTypeEnum(),
                requestDTO.getFeeDetailDTOList());

        //账单类目转换失败
        if(addBillDetailDTOList == null || addBillDetailDTOList.isEmpty()){
            throw new BizException("ACC30001");
        }

        //关联明细
        addBillAndChangeBalanceDTO.setAddBillDetailDTOList(addBillDetailDTOList);

        return addBillAndChangeBalanceDTO;
    }


    /**
     * 公共校验方法
     * @param freezeRequestDTO
     */
    private void validate(Object freezeRequestDTO){
        Errors errors = new BindException(freezeRequestDTO,"请求参数");
        springValidator.validate(freezeRequestDTO,errors);
        if(errors.hasErrors()){
            FieldError fieldError = errors.getFieldErrors().get(0);
            throw new IllegalArgumentException(fieldError.getField().concat(fieldError.getDefaultMessage()));
        }
    }

    /**
     * 还款冻结入参校验
     * @param requestDTO
     */
    private void validateRefundFreeze(TransFreezeRequestDTO requestDTO){
        this.validate(requestDTO);
        if(requestDTO.getOrderType() != OrderTypeEnum.REPAYMENT && requestDTO.getOrderType() != OrderTypeEnum.GUARANTEE){
            throw new IllegalArgumentException("无效的orderType");
        }
        if(requestDTO.getOrderType() == OrderTypeEnum.REPAYMENT && requestDTO.getOrderRefundTypeEnum() == null){
            throw new IllegalArgumentException("refundType不能为空");
        }
    }

    /**
     * 回款记账入参校验
     * @param requestDTO
     */
    private void validateReceivedRepaymentSuccessAccounting(ReceivedRepaymentSuccessAccountingRequestDTO requestDTO){
        this.validate(requestDTO);
        if(requestDTO.getOrderType() != OrderTypeEnum.RECEIVED_REPAYMENT){
            throw new IllegalArgumentException("无效的orderType");
        }
    }


    /**
     * 冻结补单
     */
    public void transFreezeResultCheckJob() {
        List<TransFreezeOrder> transFreezeOrderList = transFreezeLocalService.listOrdersForFreezeCheckJob();
        if(transFreezeOrderList == null || transFreezeOrderList.isEmpty()){
            log.info("交易冻结补单总记录数为0");
            return;
        }
        log.info("交易冻结补单总记录数：{}",transFreezeOrderList.size());
        for(TransFreezeOrder transFreezeOrder : transFreezeOrderList){
            try{
                log.info("交易冻结补单明细：{}",JSON.toJSONString(transFreezeOrder));
                //查询存管状态
                QueryTransactionRequest queryRequest = new QueryTransactionRequest();
                queryRequest.setRequestNo(transFreezeOrder.getRequestNo());
                queryRequest.setPlatformUserNo(transFreezeOrder.getPlatformUserNo());
                CompletableFuture<QueryPretransactionResponse> responseCompletableFuture =  lanMaoDirectService.queryPretransaction(queryRequest);
                QueryPretransactionResponse response = null;
                try{
                    log.info("交易冻结查询接口请求参数：{}",JSON.toJSONString(queryRequest));
                    response = responseCompletableFuture.get();
                    log.info("交易冻结查询接口响应参数：{}",JSON.toJSONString(response));
                }catch(Exception e){
                    log.error("交易冻结补单存管查询失败：{}", JSON.toJSONString(transFreezeOrder), e);
                    continue;
                }
                //交易不存在，冻结失败
                if (LanMaoErrorCodeEnum.QUERY_OBJECT_NOT_EXIST.getCode().equals(response.getErrorCode())){
                    transFreezeLocalService.freezeFailure(transFreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
                    continue;
                }
                //查询
                if(response.isSuccess()){
                    if (response.getRecords() == null || response.getRecords().isEmpty()) {
                        log.error("交易冻结查询接口返回明细为空,request:{},response:{}",JSON.toJSONString(queryRequest),JSON.toJSONString(response));
                        continue;
                    }
                    QueryPretransactionResponse.PretransactionDetail detail = response.getRecords().get(0);
                    //冻结成功
                    if("FREEZED".equals(detail.getStatus())){
                        TransFreezeRequestDTO transFreezeRequestDTO = this.queryRefundFreezeParam(transFreezeOrder.getOrderId());
                        if(transFreezeRequestDTO == null){
                            log.error("交易冻结补单任务查询冻结参数返回空,orderId:{}",transFreezeOrder.getOrderId());
                            continue;
                        }
                        log.info("交易冻结补单任务根据交易中心查询接口组装冻结请求对象,orderId:{},{}"
                                ,transFreezeOrder.getOrderId(),JSON.toJSONString(transFreezeRequestDTO));
                        //生成记账单，调用冻结成功方法
                        AddBillAndChangeBalanceDTO billAndChangeBalanceDTO =
                                this.generateFreezeSuccessBill(transFreezeRequestDTO,transFreezeOrder.getRequestNo());
                        transFreezeLocalService.freezeSuccess(transFreezeOrder.getId(),billAndChangeBalanceDTO);
                    }
                    //冻结失败
                    else if("FAIL".equals(detail.getStatus())){
                        transFreezeLocalService.freezeFailure(transFreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
                    }
                    else{
                        log.info("交易冻结查询接口返回状态不明无法处理：{}",JSON.toJSONString(response));
                    }
                }
            }catch(Exception e){
                log.error("交易冻结补单异常：{}",JSON.toJSONString(transFreezeOrder),e);
            }
        }
    }


    /**
     * 解冻补单
     */
    public void transUnfreezeResultCheckJob() {
        List<TransUnfreezeOrder> transUnfreezeOrderList = transUnfreezeLocalService.listOrdersForUnfreezeCheckJob();
        if(transUnfreezeOrderList == null || transUnfreezeOrderList.isEmpty()){
            log.info("交易解冻补单总记录数为0");
            return;
        }
        log.info("交易解冻补单总记录数：{}",transUnfreezeOrderList.size());
        for(TransUnfreezeOrder transUnfreezeOrder : transUnfreezeOrderList){
            try{
                log.info("交易解冻补单明细：{}",JSON.toJSONString(transUnfreezeOrder));
                //查询存管状态
                QueryTransactionRequest queryRequest = new QueryTransactionRequest();
                queryRequest.setRequestNo(transUnfreezeOrder.getRequestNo());
                queryRequest.setPlatformUserNo(transUnfreezeOrder.getPlatformUserNo());
                CompletableFuture<QueryCancelPretransactionResponse> responseCompletableFuture =  lanMaoDirectService.queryCancelPretransaction(queryRequest);
                QueryCancelPretransactionResponse response = null;
                try{
                    log.info("交易解冻查询接口请求参数：{}",JSON.toJSONString(queryRequest));
                    response = responseCompletableFuture.get();
                    log.info("交易解冻查询接口响应参数：{}",JSON.toJSONString(response));
                }catch(Exception e){
                    log.error("交易解冻补单存管查询失败：{}", JSON.toJSONString(transUnfreezeOrder), e);
                    continue;
                }
                //交易不存在，解冻失败
                if (LanMaoErrorCodeEnum.QUERY_OBJECT_NOT_EXIST.getCode().equals(response.getErrorCode())){
                    transUnfreezeLocalService.unfreezeFailure(transUnfreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
                    continue;
                }

                //查询
                if(response.isSuccess()){
                    if (response.getRecords() == null || response.getRecords().isEmpty()) {
                        log.error("交易解冻查询接口返回明细为空,request:{},response:{}",JSON.toJSONString(queryRequest),JSON.toJSONString(response));
                        continue;
                    }
                    QueryCancelPretransactionResponse.CancelPretransactionDetail detail = response.getRecords().get(0);
                    //解冻成功
                    if("SUCCESS".equals(detail.getStatus())){
                        transUnfreezeLocalService.unfreezeSuccess(transUnfreezeOrder.getFreezeId(),transUnfreezeOrder.getId());
                    }
                    //解冻失败
                    else if("FAIL".equals(detail.getStatus())){
                        transUnfreezeLocalService.unfreezeFailure(transUnfreezeOrder.getId(),response.getErrorCode(),response.getErrorMessage());
                    }
                    else{
                        log.info("交易解冻查询接口返回状态无法处理：{}",JSON.toJSONString(response));
                    }
                }
            }catch(Exception e){
                log.error("交易解冻补单异常：{}",JSON.toJSONString(transUnfreezeOrder),e);
            }
        }
    }



}
